#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <chrono>
#include <iostream>
#include <string>
#include <netinet/tcp.h>

constexpr int DATA_BUFFER_SIZE = 4096;

int main(int argc, char **argv) {
    if (argc < 2) {
        std::cout << "Usage: client <host> [nodelay:1]\n";
        return 1;
    }

    const std::string empty = "";
    const std::string longs = "01234567899876543210012345678998765432100123456789"
                              "9876543210012345678998765432100123456789987654321";

    int socket = ::socket(PF_INET, SOCK_STREAM, 0);

    struct sockaddr_in server_addr;
    socklen_t server_addr_size  = sizeof(server_addr);
    bzero((char*)&server_addr, server_addr_size);
    server_addr.sin_family      = AF_INET;
    server_addr.sin_port        = htons(8080);
    server_addr.sin_addr.s_addr = inet_addr(argv[1]);

    // setsockopt: no_delay
    if (argc == 3) {
        int flag = *argv[2] - '0';
        auto ret = ::setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag));
        auto res = ret == 0 ? "True" : "False";
        std::cout << "setsockopt: no_delay="<< flag << ", set success: " << res << "\n";
    }

    connect(socket, (struct sockaddr*)&server_addr, server_addr_size);
    const std::string msg = "abcdefghijklmnopqrstuvwxyz";
    int len = msg.length();
    int cnt = 0;
    std::string buf;
    size_t ret;
    std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
    std::chrono::steady_clock::time_point t2;
    // write - write - read
    for (int i=0; i < len; i++) {
        std::string seg = empty + msg[i];
        ret = write(socket, seg.data(), seg.length());
        if ((i+1) % 2 != 0) {
            continue;
        }
        char buffer[DATA_BUFFER_SIZE];
        ret = read(socket, buffer, DATA_BUFFER_SIZE-1);
        cnt += ret;
        buffer[ret] = '\0';
        buf += std::string(buffer, ret);

        t2 = std::chrono::steady_clock::now();
        auto ts = std::chrono::duration<double, std::milli>(t2-t1).count();
        std::cout << "recv: " << buf << ", len=" << buf.length() << ", span: " << ts << " (ms)\n";
        buf.clear();
        cnt = 0;
        t1  = std::chrono::steady_clock::now();
    }
    close(socket);

    return 0;
}
